﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Windows.Forms;
using Kangaroo.Controls;
using Kangaroo.IDAL;
using Kangaroo.Model;

namespace Kangaroo.Shell
{
    partial class Main
    {
        class PeriodView : ChartSubView
        {
            private const long AlarmKeyNonExist = -1;
            private const string TimeFormat = "HH:mm:ss";

            /// <summary>
            /// 已知的最新Alarm Key
            /// </summary>
            private long _lastAlarmKey = AlarmKeyNonExist;
            private TreeNode _timeNodeToBeSelected;

            public PeriodView(Main mainWin, ChartView parentView)
                : base(mainWin, parentView)
            {
            }

            public override void Refresh()
            {
                RefreshAlarm();

                RefreshSignal();
            }

            private void RefreshSignal()
            {
                if(ParentView.CurrentChannel == null)
                {
                    return;
                }
                _timeNodeToBeSelected = null;
                DAL.Data.Signal.ListTimePointsOfChannelAsync(ParentView.CurrentChannel).Then(
                    timePoints => MainWin.BeginInvoke((Action)delegate
                    {
                        try
                        {
                            var currentSelectedTimePoint = MainWin.timeTree.SelectedNode != null
                                ? MainWin.timeTree.SelectedNode.GetFirstLeaf().Tag as SignalInfo
                                : null;

                            var timePointNodes = PrepareTreeNodesFromTimePoints(timePoints, currentSelectedTimePoint);
                            if (MainWin.realtimeDisplayToolStripMenuItem.Checked)
                            {
                                _timeNodeToBeSelected = TreeNodeHelper.GetFirstLeaf(timePointNodes[0]);
                            }
                            MainWin.timeTree.SetTreeNodes(timePointNodes, _timeNodeToBeSelected);

                            MainWin.OnDataConnectionSuccess();
                        }
                        catch (Exception ex)
                        {
                            MainWin.UIFailureHandler(ex);
                        }
                    }), MainWin.DataErrorHandler);
            }

            private void RefreshAlarm()
            {
                if(_lastAlarmKey != AlarmKeyNonExist)
                {
                    DisplayNewAlarms();
                }
                else
                {
                    SetupAlarmReportStartPoint();
                }
            }

            private void SetupAlarmReportStartPoint()
            {
                DAL.Data.Alarm.ListLastAlarmForEachChannelAsync().Then(
                    lastAlarmForEachChannel => MainWin.BeginInvoke((Action)delegate
                    {
                        try
                        {
                            if (_lastAlarmKey == AlarmKeyNonExist)
                            {
                                _lastAlarmKey = lastAlarmForEachChannel
                                    .Select(p => p.Key).DefaultIfEmpty(AlarmKeyNonExist).Max();
                            }
                            MainWin.OnDataConnectionSuccess();
                        }
                        catch (Exception ex)
                        {
                            MainWin.UIFailureHandler(ex);
                        }
                    }), MainWin.DataErrorHandler);
            }

            private void DisplayNewAlarms()
            {
                DAL.Data.Alarm.ListAlarmsAfterAsync(_lastAlarmKey).Then(
                    alarms => MainWin.BeginInvoke((Action)delegate
                    {
                        try
                        {
                            MainWin.OnDataConnectionSuccess();
                            foreach (var alarm in alarms)
                            {
                                MainWin._eventViewManager.RecordAlarm(alarm);
                                _lastAlarmKey = Math.Max(_lastAlarmKey, alarm.Key);
                            }
                        }
                        catch (Exception ex)
                        {
                            MainWin.UIFailureHandler(ex);
                        }
                    }), MainWin.DataErrorHandler);
            }

            private TreeNode[] PrepareTreeNodesFromTimePoints(
                IEnumerable<SignalInfo> timePoints, SignalInfo currentSelectedTimePoint)
            {
                return timePoints.GroupBy(t => t.PdTime.Date)
                    .OrderByDescending(t => t.Key)
                    .Select(groupingByDate => CreateDateNode(groupingByDate, currentSelectedTimePoint))
                    .ToArray();
            }

            private TreeNode CreateDateNode(IGrouping<DateTime, SignalInfo> groupingByDate,
                SignalInfo currentSelectedTimePoint)
            {
                return new TreeNode(
                    groupingByDate.Key.ToShortDateString(),
                    groupingByDate.OrderByDescending(t => t.PdTime.TimeOfDay)
                        .Select(timePoint => CreateTimeNode(timePoint, currentSelectedTimePoint))
                        .ToArray());
            }

            private TreeNode CreateTimeNode(SignalInfo timePoint,
                SignalInfo currentSelectedTimePoint)
            {
                var timeNode = new TreeNode(timePoint.PdTime.ToString(TimeFormat)) { Tag = timePoint };
                if(currentSelectedTimePoint != null && timePoint.Key == currentSelectedTimePoint.Key)
                {
                    _timeNodeToBeSelected = timeNode;
                }
                return timeNode;
            }

            public override void Activate()
            {
                MainWin.timeTree.Show();
                MainWin.eventList.Show();

                MainWin.historyTrendTableLayoutPanel.Hide();
                MainWin.characteristicChartsTableLayoutPanel.Show();
                MainWin.characteristicChartsTableLayoutPanel.Dock = DockStyle.Fill;

                MainWin.splitTrees.Panel2Collapsed = false;
                MainWin.splitTreeEvent.Panel2Collapsed = false;

                ParentView.ChannelSelected += MainWin_ChannelSelected;
                MainWin.timeTree.AfterSelect += timeTree_AfterSelect;
            }

            public override void Deactivate()
            {
                ParentView.ChannelSelected -= MainWin_ChannelSelected;
                MainWin.timeTree.AfterSelect -= timeTree_AfterSelect;
                base.Deactivate();
            }

            void timeTree_AfterSelect(object sender, TreeViewEventArgs e)
            {
                try
                {
                    if (e.Node.Nodes.Count > 0)
                    {
                        return;
                    }
                    DAL.Data.Signal.GetSignalAsync(((SignalInfo)e.Node.Tag).Key).Then(
                        signal => MainWin.BeginInvoke((Action)delegate
                        {
                            try
                            {
                                if (signal.PrpsGraph == null)
                                {
                                    signal.PrpsGraph = new PrpsGraph(signal.PrpsGraphRawData);
                                }
                                MainWin.GenerateCharacteristicSpectrum(signal);

                                MainWin.OnDataConnectionSuccess();
                            }
                            catch (Exception ex)
                            {
                                MainWin.UIFailureHandler(ex);
                            }
                        }), MainWin.DataErrorHandler);
                }
                catch (Exception ex)
                {
                    MainWin.UIFailureHandler(ex, true);
                }
            }

            void MainWin_ChannelSelected(object sender, EventArgs<ChannelInfo> e)
            {
                try
                {
                    Refresh();
                }
                catch (Exception ex)
                {
                    MainWin.UIFailureHandler(ex, true);
                }
            }
        }

    }
}
